use serde::{Deserialize, Serialize};

use crate::prelude::*;

/// Wrapper to marshal something serde-able in JSON form.
// TODO make a version of this that doesn't require a clone to instantiate, maybe using Cow
pub struct SerdeJson<T> {
    v: T,
}

impl<T> SerdeJson<T> {
    pub fn new(v: T) -> Self {
        Self { v }
    }

    pub fn inner(&self) -> &T {
        &self.v
    }

    pub fn inner_mut(&mut self) -> &mut T {
        &mut self.v
    }

    pub fn into_inner(self) -> T {
        self.v
    }
}

impl<T: Serialize> Encode for SerdeJson<T> {
    fn encode<E: Encoder>(&self, enc: &mut E) -> Result<(), CodecError> {
        // TODO rework types to avoid alloc if possible
        let buf = serde_json::to_vec(&self.v).map_err(|e| CodecError::from_tostr(&e))?;
        enc.push_var_buf(&buf)
    }
}

impl<'de, T: Deserialize<'de>> DecodeRef<'de> for SerdeJson<T> {
    fn decode_ref<'c, D: Decoder<'de>>(dec: &'c mut D) -> Result<Self, CodecError>
    where
        'de: 'c,
    {
        let buf = dec.take_var_buf()?;
        let v = serde_json::from_slice(buf).map_err(|e| CodecError::from_tostr(&e))?;
        Ok(Self { v })
    }
}
